package edu.unika.aifb.graphindex.searcher.keyword.model;

/**
 * Copyright (C) 2009 Lei Zhang (beyondlei at gmail.com)
 * 
 * This file is part of the graphindex project.
 *
 * graphindex is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2
 * as published by the Free Software Foundation.
 * 
 * graphindex is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with graphindex.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import edu.unika.aifb.graphindex.model.IAttribute;
import edu.unika.aifb.graphindex.model.IEntity;
import edu.unika.aifb.graphindex.model.INamedConcept;
import edu.unika.aifb.graphindex.model.IRelation;
import edu.unika.aifb.graphindex.model.IResource;


public class KeywordElement implements Comparable<KeywordElement>, Serializable {
	private static final long serialVersionUID = 8594203186544962955L;
	// TODO make these subclasses, that's what they are there for
	public static final int CONCEPT = 0;
	public static final int RELATION = 1;
	public static final int ENTITY = 2;
	public static final int ATTRIBUTE = 3;

	private String uri;
	private double matchingScore;
	private String elementType;

	protected int type;

	private Set<String> m_inProperties, m_outProperties;
	private Map<String,Double> m_inPropertyWeights = new HashMap<String,Double>();
	private Map<String,Double> m_outPropertyWeights = new HashMap<String,Double>();
	
	public Set<IEntity> entities = new HashSet<IEntity>();
	public Map<String, IEntity> entityUri2Entity = new HashMap<String, IEntity>();
	public Set<IAttribute> attributes = new HashSet<IAttribute>();
	public Set<INamedConcept> concepts = new HashSet<INamedConcept>();
	public Set<IRelation> relations = new HashSet<IRelation>();
	private KeywordSegment keywordSegment;
	
	public KeywordElement(String uri, int type, double score) {
		this.uri = uri;
		this.type = type;
		this.matchingScore = score;
	}
	
	public KeywordElement(String uri, int type) {
		this.uri = uri;
		this.type = type;
	}
	
	

	public KeywordSegment getKeywordSegment() {
		return keywordSegment;
	}

	public void setKeywordSegment(KeywordSegment keywordSegment) {
		this.keywordSegment = keywordSegment;
	}

	public int getType(){
		return type;
	}
	
	public void setType(int type) {
		this.type = type;
	}
	
	public String getElementType() {
		return elementType;
	}
	
	public void setElementType(String elementType) {
		this.elementType = elementType;
	}
	
	
	public void setMatchingScore(double score){
		this.matchingScore = score;
	}

	public double getMatchingScore(){
		return matchingScore;
	}
	
	public Set<String> getInProperties() {
		return m_inProperties;
	}
	
	public Set<String> getOutProperties() {
		return m_outProperties;
	}

	public void addInProperties(Collection<String> properties) {
		if (m_inProperties == null)
			m_inProperties = new HashSet<String>();
		m_inProperties.addAll(properties);
		
		for (String property : properties) {
			Double count = m_inPropertyWeights.get(property);
			if (count == null)
				count = 0.0;
			count++;
			m_inPropertyWeights.put(property, count);
		}
	}

	public void addOutProperties(Collection<String> properties) {
		if (m_outProperties == null)
			m_outProperties = new HashSet<String>();
		m_outProperties.addAll(properties);

		for (String property : properties) {
			Double count = m_outPropertyWeights.get(property);
			if (count == null)
				count = 0.0;
			count++;
			m_outPropertyWeights.put(property, count);
		}
	}
	
	public Map<String,Double> getInPropertyWeights() {
		return m_inPropertyWeights;
	}
	
	public Map<String,Double> getOutPropertyWeights() {
		return m_outPropertyWeights;
	}
	
	public void calcPropertyWeights() {
		calcPropertyWeights(m_inPropertyWeights);
		calcPropertyWeights(m_outPropertyWeights);
	}
	
	private void calcPropertyWeights(Map<String,Double> propertyWeights) {
		double max = 0.0;
		for (String property : propertyWeights.keySet())
			max = Math.max(max, propertyWeights.get(property));
		for (String property : propertyWeights.keySet())
			propertyWeights.put(property, propertyWeights.get(property) / max);
	}
	
	public String getUri() {
		return uri; 
	} 
	
		
	public String toString(){
		return uri + " " + entities.size();	
	}

	public boolean equals(Object object){
		if(this == object) return true;
		if(object == null) return false;
		if(!(object instanceof KeywordElement)) return false;
		
		KeywordElement vertex = (KeywordElement)object;
		return uri.equals(vertex.getUri()) && (this.elementType == vertex.elementType || this.elementType.equals(vertex.elementType)) && keywordSegment.equals(vertex.getKeywordSegment());
	}
	
	public int hashCode(){
		return uri.hashCode() + (elementType != null ? elementType.hashCode() : 0) + (keywordSegment != null ? keywordSegment.hashCode() : 0);
	}

	public int compareTo(KeywordElement o) {
		return this.getUri().compareTo(o.getUri());
	}
	
	public void sortEntities(){
		SortedSet<IEntity> sortedEntities = new TreeSet<IEntity>(new ResourceComparator());
		sortedEntities.addAll(entities);
		entities.clear();
		entities = sortedEntities;
		
		for(IEntity entity : entities)
			entityUri2Entity.put(entity.getUri(), entity);
	}

}

class ResourceComparator implements Comparator<IResource>{
@Override
	public int compare(IResource o1, IResource o2) {
		int i = ((Comparable<Double>)o2.getScore()).compareTo(o1.getScore());
		if(i != 0)
			return i;
		return o1.getUri().compareTo(o2.getUri());
	}
	
}
